#version 440 core

#define LOC_X 16
#define LOC_Y 16

#define GRID_SIZE_X 64
#define GRID_SIZE_Y 64

layout(local_size_x=LOC_X, local_size_y=LOC_Y) in;

layout(binding=0) uniform sampler2D levelSetTexture;
layout(binding=0, r32ui) uniform coherent uimage2D levelSetStateImage;

layout(binding=0, offset=0) uniform atomic_uint finishedNodesCounter;

layout(std430, binding=0) buffer finishedNodesBuffer
{
	ivec2 finishedNodes[];
};

void main(void)
{
	ivec2 gid = ivec2(gl_GlobalInvocationID.xy);
	bvec2 cond = lessThan(gid, ivec2(GRID_SIZE_X, GRID_SIZE_Y));
	if (cond.x && cond.y)
	{
		ivec2 off1 = gid + ivec2(1,0);
		ivec2 off2 = gid + ivec2(0,1);
		ivec2 off3 = gid + ivec2(1,1);

		// level set values at the four corners
		vec4 levelSetValues = textureGather(levelSetTexture, (gl_GlobalInvocationID.xy+vec2(1.0,1.0))*vec2(1.0/(GRID_SIZE_X+1.0), 1.0/(GRID_SIZE_Y+1.0)));
		
		ivec4 signLevelSetValues = ivec4(sign(levelSetValues));
		int sum = signLevelSetValues.x + signLevelSetValues.y + signLevelSetValues.z + signLevelSetValues.w;
		
		if (sum != 4 && sum !=-4)
		{
			if (imageAtomicExchange(levelSetStateImage, gid, 1u) == 0)
			{
				uint index = atomicCounterIncrement(finishedNodesCounter);
				finishedNodes[index] = gid;
			}
			if (imageAtomicExchange(levelSetStateImage, off1, 1u) == 0)
			{
				uint index = atomicCounterIncrement(finishedNodesCounter);
				finishedNodes[index] = off1;
			}
			if (imageAtomicExchange(levelSetStateImage, off2, 1u) == 0)
			{
				uint index = atomicCounterIncrement(finishedNodesCounter);
				finishedNodes[index] = off2;
			}
			if (imageAtomicExchange(levelSetStateImage, off3, 1u) == 0)
			{
				uint index = atomicCounterIncrement(finishedNodesCounter);
				finishedNodes[index] = off3;
			}
		}
	}
}